﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Miris.HumanMilkAnalyser.DataModel;
using Miris.HumanMilkAnalyser.Repository.Interface;
using Miris.HumanMilkAnalyser.Service.Interface;
using Miris.HumanMilkAnalyser.Service.Shared;
using Miris.HumanMilkAnalyser.Service.Validation;

namespace Miris.HumanMilkAnalyser.Service
{
    public enum MilkSample
    {
        Front = 1,
        Middle = 2,
        End = 3,
        Full = 4
    }

    public enum MilkStage
    {
        Unmature = 1,
        Transitional = 2,
        Mature = 3
    }

    public class AnalysisResultService : ServiceBase<AnalysisResult>, IAnalysisResultService
    {
        public AnalysisResultService(IRepositoryFactory repositoryFactory) : base(repositoryFactory, new AnalysisResultValidator()) { }

        /// <summary>
        /// Add new entity.
        /// </summary>
        /// <param name="entity">The new entity will be added into database.</param>
        /// <returns>The id of the new added entity.</returns>
        public override AnalysisResult Add(AnalysisResult entity)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSessionWithTransaction();
                var analysisResultRepository = RepositoryFactory.CreateAnalysisResultRepository();
                var unassignedSampleNumberRepository = RepositoryFactory.CreateUnassignedSampleNumberRepository();

                // Check if the specified sample number has been assigned already.
                var existingSampleNumberCount = analysisResultRepository.GetRowCount(p => p.SampleNumber == entity.SampleNumber);

                if (existingSampleNumberCount == 0)
                {
                    var addedEntity = Add(RepositoryFactory.CreateRepositoryBase<AnalysisResult>(), entity);

                    // Remove this sample number from UnassignedSampleNumber table
                    var unassignedSampleNumber = unassignedSampleNumberRepository.Get(entity.SampleNumber);

                    if (unassignedSampleNumber != null)
                    {
                        unassignedSampleNumberRepository.Delete(unassignedSampleNumber);
                    }

                    RepositoryFactory.Commit();

                    return addedEntity;
                }
                else
                {
                    throw new ArgumentException(string.Format("样本号{0}已被分配", entity.SampleNumber));
                }
            }
        }

        /// <summary>
        /// Query AnalysisResult by lambda expression, the returned data includes navigation property AnalysisResultDiagnosticMessages.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts TDataModel and return boolean.</param>
        /// <returns>An IList list of data.</returns>
        public override IList<AnalysisResult> Query(Expression<Func<AnalysisResult, bool>> expression)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();
                return RepositoryFactory.CreateRepositoryBase<AnalysisResult>().Query(expression, "AnalysisResultDiagnosticMessages").ToList();
            }
        }

        /// <summary>
        /// Delete the specified entity.
        /// </summary>
        /// <param name="entity">The entity will be deleted from database.</param>
        public override void Delete(AnalysisResult entity)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();
                CommonService.DeleteAnalysisResult(RepositoryFactory, entity.SampleNumber);
                RepositoryFactory.Commit();
            }
        }

        /// <summary>
        /// Delete the specified entity list.
        /// </summary>
        /// <param name="entities">The entity list will be deleted from database.</param>
        public override void Delete(IEnumerable<AnalysisResult> entities)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();

                foreach (var entity in entities)
                {
                    CommonService.DeleteAnalysisResult(RepositoryFactory, entity.SampleNumber);
                }

                RepositoryFactory.Commit();
            }
        }

        /// <summary>
        /// Get the all analysis result count based on provided patient number.
        /// </summary>
        /// <param name="patientNumber">The provided patient number and its related analysis result count will be returned.</param>
        /// <returns>All analysis result count based on provided patient number.</returns>
        public int GetAllAnalysisCount(string patientNumber)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();
                return RepositoryFactory.CreateAnalysisResultRepository().GetRowCount(p => p.PatientNumber.ToLower() == patientNumber.ToLower());
            }
        }

        /// <summary>
        /// Get the last analysis result based on provided patient number.
        /// </summary>
        /// <param name="patientNumber">The provided patient number and its related analysis result will be returned.</param>
        /// <returns>The last analysis result based on provided patient number. NULL will be returned if no matched data.</returns>
        public AnalysisResult GetLastAnalysisResult(string patientNumber)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();
                return RepositoryFactory.CreateAnalysisResultRepository().Query(p => p.PatientNumber.ToLower() == patientNumber.ToLower()).FirstOrDefault();
            }
        }

        /// <summary>
        /// Get all related AnalysisResults by provided patient number and return the specified rows.
        /// </summary>
        /// <param name="patientNumber">The provided patient number.</param>
        /// <param name="rowCount">How many rows will be returned.</param>
        /// <returns>AnalysisResult list contains all related AnalysisResults.</returns>
        public IList<AnalysisResult> GetAllRelatedTestResultsByPatientNumber(string patientNumber, int? rowCount)
        {
            using (RepositoryFactory)
            {
                RepositoryFactory.OpenSession();

                var result = RepositoryFactory.CreateAnalysisResultRepository().Query(p => p.PatientNumber == patientNumber, "AnalysisResultDiagnosticMessages")
                    .OrderByDescending(p => p.TestDate);

                if (rowCount.HasValue && rowCount.Value > 0)
                {
                    return result.Take(rowCount.Value).ToList();
                }
                else
                {
                    return result.ToList();
                }
            }
        }
    }
}
